Week 3: Technical Art - Landscapes, Foliage & Procedural Content Generation

Building Massive Open Worlds with Efficient Terrain Systems

Session Objectives

  • Master landscape system architecture and heightmap workflows
  • Understand material layer blending and Runtime Virtual Texturing
  • Learn foliage system optimization and placement techniques
  • Explore PCG Framework for procedural content generation
  • Apply performance optimization strategies for large-scale environments

Table of Contents

PART 1: LANDSCAPE SYSTEMS
1. Landscape System Fundamentals
2. Heightmaps
3. Landscape Materials
4. Weight Maps & Layer Painting
5. Auto-Materials
6. Runtime Virtual Texturing
7. Landscape LOD System
8. World Partition & Streaming
PART 2: FOLIAGE SYSTEMS
9. Foliage System Fundamentals
10. Foliage Types
11. Foliage Placement Methods
12. Foliage LOD & Culling
13. Foliage Materials
PART 3: PCG & OPTIMIZATION
14. PCG Framework Overview
15. PCG Nodes & Operations
16. Optimization Strategies
17. Production Workflows

PT1: Landscape system

Landscape System Fundamentals

What is the Landscape System?

The Landscape System is Unreal Engine’s specialized terrain rendering framework, designed to create and manage large-scale outdoor environments using heightmap-based geometry.

Core Characteristics:

  • Heightmap-based representation: Terrain defined by 2D height data
  • Continuous LOD system: Seamless detail reduction with distance
  • Streaming support: Efficient memory management for large worlds
  • Integrated layer blending: Built-in material painting system
  • Component-based architecture: Modular rendering and streaming units

UE5 Open World terrain study by Pexy43

Pexy43, “UE5 Open World — Terrain Study”, ArtStation, viewed 13 October 2025, https://www.artstation.com/artwork/Pexy43

Landscape Architecture

The Landscape System uses a hierarchical structure for efficient rendering and streaming.

![Placeholder Image 002: Diagram showing landscape component hierarchy from quads to complete terrain]

Landscape Size Configurations

Use Case Component Count Total Size Quad Count Memory Estimate
Small Scene 4×4 (16) 630m × 630m ~64,000 ~50MB
Medium Level 8×8 (64) 1.26km × 1.26km ~256,000 ~200MB
Large Open World 16×16 (256) 2.52km × 2.52km ~1,000,000 ~800MB
Massive World 32×32 (1024) 5.04km × 5.04km ~4,000,000 ~3.2GB

Memory estimates include heightmap and weight map data. Use World Partition for worlds exceeding 8×8km.

Using Landscapes Over Static Meshes

Landscape System

The Landscape System uses heightmaps with continuous LOD, integrated layer painting, and optimized streaming. Memory per square meter is low, making it efficient for large outdoor areas.

Constraints: 2.5D only (no overhangs/caves) with a fixed component structure tied to height-based terrain.

Best for open worlds above 1 km²: rolling hills and mountains derived from heightmap data and large traversable terrain.

Static Mesh Terrain

Static meshes provide full 3D freedom, enabling overhangs, caves, custom UVs, and precise geometric control with modular construction.

Trade‑offs: manual LOD chains, higher memory usage, and no built‑in layer painting; scaling to very large areas is less efficient.

Best for caves and tunnel networks, modular terrain pieces, small detailed zones, custom collision, and architectural spaces.

Heightmaps

What are Heightmaps?

A heightmap is a grayscale image where pixel intensity represents terrain elevation. Each pixel corresponds to a vertex height in the landscape.

Heightmap Encoding:

  • Black pixels (0): Lowest elevation
  • White pixels (255): Highest elevation
  • Gray pixels (128): Mid-range elevation
  • 16-bit format: 65,536 discrete height levels
  • 8-bit format: 256 height levels (avoid for production)

Thick terrain visualization from Three.js discussion

“Thick terrain with height map” thread, Three.js Forum, viewed 13 October 2025, https://discourse.threejs.org/t/create-a-thick-terrain-with-height-map/43528

How to create and import Heightmaps?

External Heightmap Creation

Recommended Tools:

Gaea (Procedural Terrain)

  • Advanced erosion simulation
  • Realistic geological features
  • Node-based workflow
  • Export: 16-bit PNG or RAW

World Machine (Industry Standard)

  • Macro and micro detail control
  • Extensive device library
  • Tiled terrain support
  • Export: 16-bit PNG, RAW, TIFF

Houdini (Technical Artists)

  • Complete procedural control
  • Custom algorithms
  • Integration with other tools
  • Export: Multiple formats

Real-World Data (Geographic)

  • USGS elevation data
  • Satellite heightmaps
  • Requires processing and scaling
  • Export: GeoTIFF to 16-bit PNG

Gaea Node-Based Workflow Interface

QuadSpinner, “Gaea Workflow”, QuadSpinner, viewed 13 October 2025, https://quadspinner.com/Gaea/Workflow

Z-Scale in UE5 Landscapes

Z-Scale controls the vertical height range of your landscape.
It determines how 16-bit heightmap values (0–65535) convert to Unreal units (centimeters).

Formula:

Landscape Height = Heightmap Value × Z-Scale / 128

Examples:

Z = 50 → ~256 m max height (flat terrain, high precision)

Z = 100 → ~512 m max height (balanced)

Z = 200 → ~1024 m max height (mountainous terrain)

Common Import Pitfalls

How Are Landscapes Textured?

The Landscape Texturing Workflow

Landscapes in UE5 use a layer-based texturing system designed specifically for large terrains.
Unlike static meshes, landscapes don’t rely on UVs, they use weight maps to blend multiple materials seamlessly across the terrain.

We can think of it like painting in Photoshop with multiple layers:

each layer is a different material (grass, rock, dirt, snow), and weight maps act as masks controlling where each one appears.

Why Landscapes Use This System

Traditional UV mapping doesn’t scale well to kilometer-sized terrains — it causes stretching and visible seams.
Landscape materials solve this by generating texture coordinates procedurally from world position, ensuring seamless detail regardless of size.

The Three-Part System

  1. Material Layers – individual surface materials (grass, rock, dirt)
  2. Weight Maps – grayscale masks defining material placement
  3. Layer Blending – combines layers based on weight maps for smooth transitions

This system supports both artistic control (manual painting) and procedural workflows (slope or height-based material distribution).

Video Thumbnail: W-BMbadinPI

“How To Make Landscape Layer Materials with Natural Height Blending in Unreal Engine 5 ” YouTube video, uploaded by Aziel Arts, viewed 13 October 2025, https://www.youtube.com/watch?v=W-BMbadinPI

What are Weight Maps?

Weight maps are grayscale textures that control layer visibility in landscape materials, defining which material appears at each location on the terrain.

Weight Map Properties:

  • 8-bit grayscale: 256 levels of transparency per layer
  • Per-pixel control: Individual pixel-level material placement
  • Normalized blending: All layer weights sum to 1.0 at each pixel
  • Runtime editable: Artists paint weight maps directly in-editor

How Weight Maps Work:

Each landscape layer has an associated weight map. The weight map value at each pixel (0.0 to 1.0) determines how visible that layer is at that location:

Artists paint these weight maps in-editor using Landscape Paint Mode, directly controlling material distribution across the terrain.

Normalization System

Vector3 Normalize vs Normalized

Source: Unity Discussions, ‘Vector3 Normalize doesn’t work but normalized does. Why?’, viewed 13 October 2025, https://discussions.unity.com/t/vector3-normalize-doesnt-work-but-normalized-does-why/695128

At any given pixel on the landscape, all layer weights must sum to exactly 1.0 (100%). The engine enforces this automatically through normalization.

When you paint one layer, the engine doesn’t just add weight, it redistributes weight from other layers. If you paint grass at 100% strength, the engine reduces rock, dirt, and other layer weights proportionally to maintain the 1.0 sum.

This normalization ensures proper blending without gaps (black spots) or overlaps (over-bright areas).

Painting Landscape Layers

Accessing Paint Mode:

Select your landscape and press Shift+2 to enter Landscape Mode, or click the Landscape Mode icon in the toolbar and then navigating to the paint tab.

You must set up landsape blend layers in the assigned material of the landscape and then create a Landscape layer info asset (this stores the weight map) for each layer.

Paint Tool Modes:

Landscape Materials

What are Landscape Materials?

Landscape Materials are specialized materials that support layer-based blending for terrain texturing without requiring manual UV unwrapping.

Key Features:

  • Layer-based system: Multiple material layers blend using weight maps
  • Weight map control: Grayscale textures define layer visibility per-pixel
  • Landscape-specific nodes: Specialized material nodes for terrain workflows
  • Runtime painting: Artists paint layers directly on terrain in-editor
  • Automatic UV generation: World-space or landscape-space coordinate systems

Unlike standard materials that rely on mesh UV coordinates, Landscape Materials generate texture coordinates procedurally based on world position or landscape-space coordinates. This enables seamless texturing across massive terrains without UV seams or distortion.

Material Layer System

Landscape Materials organize textures into layers that blend together based on weight maps. Each layer represents a distinct material type (grass, rock, dirt, snow) with its own textures and properties.

Material Nodes for Landscapes

Landscape materials use specialized nodes and techniques to handle terrain-specific challenges: seamless texturing across massive areas, layer blending, slope-based distribution, and performance optimization. This section covers the essential nodes and material functions you’ll use to build landscape materials.

Coordinate Generation

LandscapeLayerCoords

This node generates UV coordinates for landscape textures, replacing traditional mesh UVs. The standard texture coordinate node (used to tile textures) provides UVs in the 0-1 range for the mesh however the UVs don’t scale with the landscape size, the Landscapelayercoords are designed specifically for landscape materials and provide UVs scaled to the landscape’s world size.

Unreal Engine Landscape Materials

Epic Games, “Landscape Materials in Unreal Engine”, viewed 13 October 2025, https://dev.epicgames.com/documentation/en-us/unreal-engine/landscape-materials-in-unreal-engine

Parameters:

Mapping Type determines coordinate generation method:

Custom UVType controls coordinate space:

Mapping Scale controls texture tiling:

Mapping Rotation rotates texture coordinates in degrees (0-360).

Practical Example:

To tile a grass texture every 5 meters:

Layer Blending & Control

LandscapeLayerBlend

This node blends multiple material layers based on weight maps, forming the core of landscape material systems.

Video Thumbnail: r7t9Dbcz824

Source: “Natural Aesthetics in UE5 - Part 2.1 - Landscape Layer Material Setup”, P Generally, YouTube, viewed 13 October 2025, https://www.youtube.com/watch?v=r7t9Dbcz824

Blend Modes:

LB_WeightBlend (Most Common)

LB_HeightBlend (Nicer blending, requires height texture)

Height Blend Behavior:

Height-blended layers use both weight and height data. Where two layers overlap, the layer with higher height value appears on top, simulating physical material accumulation. This creates realistic transitions where dirt settles in rock crevices or snow accumulates on peaks.

Configuration:

Add layers using the “+” button in the node properties. Each layer requires:

LandscapeLayerWeight

This node reads the weight map value for a specific layer at each pixel, enabling weight-driven material logic.

Landscape Layer Weight Node

Epic Games, “Landscape Materials in Unreal Engine”, viewed 13 October 2025, https://dev.epicgames.com/documentation/en-us/unreal-engine/landscape-materials-in-unreal-engine

Applications:

Conditional Material Logic: Increase roughness where dirt layer is present. Read dirt layer weight, multiply by roughness adjustment value, add to base roughness.

Blend Between Effects: Fade between two normal map intensities based on layer presence. Lerp between values using layer weight as alpha.

Drive Parameters: Control material parameters dynamically based on painted layer distribution. Use layer weight to drive emissive intensity, subsurface scattering strength, or displacement amount.

Example Implementation:

To increase surface roughness in areas with dirt accumulation:

  1. Add LandscapeLayerWeight node, set Layer Name to “Dirt”
  2. Multiply output by 0.3 (roughness increase amount)
  3. Add result to base roughness value
  4. Connect to material Roughness output

This creates rougher surfaces where dirt has been painted, simulating accumulated grime.

Breaking Texture Repetition

Large landscapes reveal texture tiling patterns that break immersion. Several techniques address this issue, each with different performance costs and visual results.

Texture Bombing

Tiled textures create obvious repetition patterns on large surfaces, especially when viewed at grazing angles or from above.

The Solution: Sample the same texture multiple times at different scales and rotations, then blend the samples using noise masks to eliminate repetition.

3D Environment Illustration

Source: CRDG, “3D Environment Illustration”, viewed 13 October 2025, https://3d.crdg.jp/env/2024/09/06/5379/

Performance Cost: 3× texture samples (expensive). Reserve for high-quality settings, or surfaces viewed at close range.

When to Use:

Triplanar Projection

Landscape UVs stretch on steep slopes, creating elongated, distorted textures on cliffs and vertical surfaces.

To solve this we can Project textures from three world axes (X, Y, Z) and blend based on surface normal direction.

When to Use:

Optimization: Use triplanar only for steep slopes. Blend between standard UVs (flat surfaces) and triplanar (steep surfaces) based on surface angle to reduce sample count.

Detail Textures & masks

Base textures may lack fine detail when viewed at close range, appearing blurry or soft.

We can overlay high-frequency detail textures at close range, fading them out at distance to maintain clean appearance or use masks to introduce further variation.

Fix Landscape Texture Tiling with This UE4 Macro/Micro Variation Technique

Source: World of Level Design, “Fix Landscape Texture Tiling with This UE4 Macro/Micro Variation Technique”, viewed 13 October 2025, https://www.worldofleveldesign.com/categories/ue4/landscape-macro-tiling-variation.php

Detail Texture Types:

Grunge/Dirt Overlays: Add weathering and imperfections to clean surfaces. Use multiply blend mode to darken base texture in worn areas.

Surface Imperfections: Scratches, pits, and micro-detail. Use overlay blend mode to add contrast without changing base color significantly.

Micro-Detail Normal Maps: High-frequency surface bumps. Blend with base normal map using normal map blending (not simple lerp).

Subtle Color Variation: Break up uniform color with slight hue/saturation shifts. Use very low intensity (5-10%) to avoid obvious patterns.

Performance Cost: +1 texture sample per detail texture. Minimal impact compared to texture bombing or triplanar.

Noise Functions (Procedural Variation)

Common Noise Types:

Perlin Noise - Voronoi Noise - Simple Noise

Implementation Example (Color Variation):

Generate noise using Absolute World Position as input. This ensures noise remains consistent across landscape components.

Multiply base color by remapped noise. This creates subtle color shifts across the landscape without obvious patterns.

Result: Natural color variation that breaks up uniformity without requiring additional textures or obvious repetition.

Performance Consideration: Procedural noise is cheaper than texture samples but more expensive than simple arithmetic.

Procedural Auto landscape material

Procedural distribution automatically places materials based on terrain properties (slope angle and elevation), eliminating manual painting for base material distribution. These techniques form the foundation of auto-materials.

MW Auto Material Screenshot

Source: MW Auto Material, viewed 13 October 2025, https://assetfreaks.com/unreal-engine-assets/environments/mw-auto-material-download/

Slope-Based Blending

Slope-based blending uses the landscape’s surface normal to determine material distribution. The surface normal is a vector perpendicular to the terrain surface at each point.

Slope Calculation:

The Z component of the surface normal indicates slope angle:

By reading this Z component, materials can automatically appear based on terrain steepness.

Define Slope Ranges: Determine slope ranges for each material type:

Create Blend Masks: Use the Z component to generate blend masks. For grass, use smoothstep with range 0.6-0.8. For rock, a range of 0.3-0.5 etc.

Apply to Layer Blend: Multiply each layer’s weight by its slope mask before connecting to the LandscapeLayerBlend node.

Transition Control:

Video Thumbnail: or2TJI2rwpA

Source: “UE5 Landscape Auto Material - The Beginning”, C Wonderscrap, viewed 13 October 2025, https://www.youtube.com/watch?v=or2TJI2rwpA

Height-Based Blending

Height-based blending distributes materials according to elevation, simulating natural biome zones and material accumulation patterns.

Understanding Height-Based Distribution:

The Absolute World Position node provides the pixel’s world-space coordinates. The Z component represents elevation in Unreal units (cm).

Height Zones Example:

Material Setup:

  1. Read Elevation: Add an Absolute World Position node. Use Component Mask set to “B” (Z channel) to extract elevation.

  2. Define Height Ranges: Determine elevation ranges for each material with intentional overlap for transition zones.

  3. Create Height Masks: Generate masks using elevation data. For grass, fade out at higher elevations (range 100000-150000). For snow, fade in at higher elevations (range 180000-220000).

  4. Combine with Slope Logic: Height and slope work together for realism. Snow appears on high peaks (height-based) but not on steep cliffs (slope-based). Multiply masks together.

Optimizing Landscapes

Distance-Based LOD Fading

Expensive material effects (parallax occlusion, complex blending, high-frequency detail) waste GPU cycles when rendered on distant terrain where they’re invisible. Distance-based LOD fading disables these effects beyond a certain distance, maintaining performance without sacrificing visual quality where it matters.

We can use the PixelDepth node to get the distance from camera to the current pixel in world units (cm). Divide by 100000 to convert to more manageable units (1 = 1km).

Create a fade range using Lerp or Smoothstep:

Use the fade value to lerp between detailed and simple material logic. For example, lerp between a complex normal map blend and a single normal map based on distance.

Example: Fade out parallax occlusion mapping or displacement beyond 50m. At close range, the material uses expensive height-based displacement. Beyond 50m, it switches to a simple normal map, saving GPU cycles with no visible quality loss.

Performance Impact: Can reduce landscape material cost by 30-50% for distant terrain while maintaining quality for near terrain.

Runtime virtual textures (RVT)

RVT System Components:

  • Virtual Texture: Massive logical texture (16K-32K+) representing final composited result
  • Physical Texture Pool: Small GPU memory cache (256-512MB) storing visible tiles
  • Feedback Buffer: Tracks which tiles are visible and need loading
  • Streaming System: Loads/unloads tiles based on camera view
  • Runtime Composition: Renders landscape material to virtual texture on-demand

Think of RVT like texture streaming for entire material systems. Instead of sampling every layer everywhere each frame, the system pre-renders visible areas into a cache and samples from that cache.

How does RVT compare to traditional texturing?

Traditional Landscape Material

Texture Samples:
8 layers × 3 textures = 24 samples. Each sample reads from memory and is processed every frame (≈400+ shader instructions).

Memory Usage:
All layer textures loaded. 8 layers × 3 textures × 2MB ≈ 48MB before mips; total ≈ 80–100MB per landscape.

Performance:
High shader complexity, bandwidth-heavy, scales poorly beyond 6–8 layers.

Runtime Virtual Texturing

Texture Samples:
2–3 total (RVT lookup) from a pre-composited cache; cost largely independent of layer count (≈100–150 instructions).

Memory Usage:
Physical pool 256–512MB (fixed). Streams only visible tiles; layer-count independent; supports 16+ layers.

Performance:
Lower shader cost with efficient memory; scales well and enables more complex materials.

The Trade-off:

RVT reduces per-pixel cost but adds system overhead. The physical texture pool requires dedicated GPU memory. Tile rendering and streaming add CPU/GPU work. For simple materials (2-4 layers), traditional texturing may perform better. For complex materials (8+ layers), RVT provides significant benefits.

![Placeholder Image 027: Performance comparison graph showing RVT vs traditional at different layer counts]

Landscape LOD System

What is Landscape LOD?

Landscape LOD (Level of Detail) is a continuous tessellation system that reduces geometry density with distance, maintaining visual quality while optimizing performance.

Unlike static mesh LODs that swap between discrete models, landscape LOD smoothly transitions between detail levels without visible popping. Each landscape component calculates its LOD independently based on distance to camera.

Landscape LOD Characteristics:

  • Continuous transitions: Smooth geometry reduction without popping
  • Per-component calculation: Each component has independent LOD
  • Distance-based: LOD determined by camera distance
  • Screen-space error metric: Maintains consistent visual quality
  • 0-7 LOD levels: Eight detail levels from full resolution to maximum reduction

At LOD 0, the landscape renders at full resolution (63×63 quads per component). At LOD 7, the landscape renders at minimum resolution (approximately 2×2 quads per component), reducing triangle count by over 95%.

How does Landscape LOD work?

LOD Calculation System

The landscape system calculates LOD for each component every frame based on distance to camera and screen-space error tolerance.

Screen-Space Error:

Screen-space error measures how much geometric simplification affects the final image. Lower error = more detail required, higher error = more simplification acceptable.

The system calculates: “If I reduce this component’s geometry, how many pixels will change in the final image?” If the answer is below the error threshold, LOD increases (geometry reduces).

How to configure LOD settings?

LOD Distribution Settings

Select your landscape actor and navigate to the LOD section in the Details panel.

LOD Distribution Setting:

This value controls how aggressively LOD increases with distance. Higher values = more aggressive LOD (geometry reduces faster). Lower values = more conservative LOD (maintains detail longer).

Default value: 1.0 (balanced)

LOD 0 Screen Size:

This defines the screen-space size threshold for LOD 0 (full detail). Components occupying more screen space than this value render at LOD 0.

Default: 1.0 (component fills entire screen)

Component-Specific LOD Settings

Individual landscape components can override global LOD settings for fine-tuned control. (Enable “Override LOD Distribution.”)

With this we can optimize performance by reducing detail where players rarely look while maintaining quality in important areas.

LOD Bias

LOD Bias globally shifts all LOD calculations up or down, providing quick performance adjustment.

Positive Bias (+1, +2): Increases LOD numbers (reduces detail everywhere)

Negative Bias (-1, -2): Decreases LOD numbers (increases detail everywhere)

Console Command: r.LandscapeLODBias [value]

Adjust LOD Bias at runtime to balance quality and performance based on current scene complexity or hardware capabilities.

World Partition & Streaming (most dont like it, but it is useful)

What is World Partition?

World Partition is Unreal Engine 5’s spatial partitioning and streaming system** that enables massive open worlds by automatically dividing levels into streamable cells.

Before World Partition, large levels loaded entirely into memory, limiting world size to available RAM. World Partition divides levels into a grid of cells that load and unload based on player position, enabling worlds of virtually unlimited size.

A first look at the World Partition System in UE5

Source: 80.lv (2021). A first look at the World Partition System in UE5. Available at: https://80.lv/articles/a-first-look-at-the-world-partition-system-in-ue5 [Accessed 14 Oct. 2025].

World Partition Features:

  • Automatic spatial partitioning: Engine divides level into grid cells
  • Distance-based streaming: Cells load/unload based on player distance
  • HLOD integration: Hierarchical LOD for distant geometry
  • Data layer system: Organize content into logical layers
  • One-file-per-actor: Each actor stored separately for better source control

World Partition replaces World Composition from Unreal Engine 4, providing more robust streaming, better performance, and improved workflow for large-scale environments.

How to set up World Partition?

Enable World Partition

For New Levels:

Create a new level and select “Open World” template. This automatically configures World Partition with recommended settings.

For Existing Levels:

Open your level. Navigate to World Settings → World → World Partition Setup.

Click “Enable World Partition.” The engine converts your level to World Partition format, creating the necessary data structures.

Warning: This conversion is one-way. Back up your level before converting.

Configure World Partition Grid

Grid Settings:

World Partition divides your level into a grid of cells. Configure grid parameters in World Settings → World Partition.

Cell Size: Dimensions of each streaming cell (default: 12800cm or 128m)

Loading Range: Distance at which cells begin loading (default: 25600cm or 256m)

Streaming Source: Defines what triggers cell loading (typically player camera position)

Organize Content with Data Layers

Data Layers organize level content into logical groups that can be loaded/unloaded independently.

Create Data Layers:

Open the Data Layers panel (Window → Data Layers). Create layers for different content types:

Assign Actors to Layers:

Select actors in the level. In the Data Layers panel, assign them to appropriate layers.

Layer Streaming:

Configure which layers load at what distances. Terrain loads first (largest range), props load last (smallest range). This prioritizes important content and optimizes memory usage.

HLOD Configuration

Hierarchical LOD (HLOD) generates simplified proxy meshes for distant cells, reducing draw calls and improving performance.

Enable HLOD:

In World Partition settings, enable “Enable HLOD.” Configure HLOD generation parameters:

HLOD Layer: Defines which actors participate in HLOD generation
Simplification Settings: Controls how aggressively geometry is simplified
Screen Size: Distance threshold for HLOD activation

The engine automatically generates HLOD meshes during the build process, replacing distant cells with simplified proxies.

One-File-Per-Actor Benefits:

World Partition stores each actor in a separate file, improving source control workflows. Multiple team members can work on the same level simultaneously without conflicts.

Commit actors individually rather than entire level files. This provides granular version control and easier conflict resolution.

Testing Streaming:

Test level streaming throughout development, not just at the end. Streaming issues are easier to fix early than after content is finalized.

Use “Simulate” mode to test streaming without playing. Move the camera through the level to verify cells load/unload correctly.

PART 2: FOLIAGE SYSTEMS

Foliage System Fundamentals

What is the Foliage System?

The Foliage System is a specialized rendering solution for placing and rendering massive quantities of vegetation and detail objects using instanced rendering techniques.

Traditional mesh placement creates individual actors for each object, resulting in thousands of draw calls and unacceptable performance. The Foliage System renders millions of instances with minimal draw calls through instancing technology.

UE Screenshot

Source: Fab (n.d.). Available at: https://www.fab.com/listings/683407f0-bc9e-444e-a5c3-ab384bbc8e3e [Accessed 14 Oct. 2025].

Foliage System Capabilities:

  • Instanced rendering: Millions of instances, single draw call per mesh type
  • Hierarchical culling: Efficient visibility determination using spatial structures
  • Automatic LOD: Distance-based detail reduction per instance
  • Paint-based placement: Intuitive brush-based distribution workflow
  • Procedural generation: Rule-based automatic population
  • Runtime modification: Dynamic instance addition/removal during gameplay

A forest containing 100,000 trees might require 100,000 draw calls with traditional placement. The Foliage System renders the same forest with 1-2 draw calls, enabling dense vegetation impossible with standard techniques.

Manual Actor Placement

Rendering: One draw call per actor with per-actor overhead and no automatic instancing—performance collapses at scale.

Memory: Full actor data per instance (transform, components, properties) → high per-object cost that scales poorly.

Workflow: Precise, per-actor control and manipulation; time-consuming for large quantities; best for hero objects.

Best For: Unique/important objects, items needing individual behavior, and small quantities (< 100 instances).

Foliage System

Rendering: Instanced rendering—one draw call per mesh type with automatic batching; excellent at scale.

Memory: Minimal per-instance data (transform + variation) for low memory cost and great scaling.

Workflow: Brush painting and procedural generation for fast, consistent large-area coverage.

Best For: Vegetation and ground cover, thousands of instances, background detail (forests, grass, rocks, debris).

Hybrid Approach:

Use manual placement for hero trees and landmark vegetation requiring individual attention. Use Foliage System for background forests and ground cover. This combines artistic control with performance efficiency.

Instanced Rendering: ISM vs HISM

Instanced Static Mesh (ISM)

ISM renders multiple instances of the same mesh with a single draw call, providing the foundation for foliage rendering.

How ISM Works:

The GPU receives one mesh and an array of transforms (position, rotation, scale). It renders the mesh multiple times using different transforms, all in a single draw call.

Performance Characteristics:

Hierarchical Instanced Static Mesh (HISM)

HISM extends ISM with spatial hierarchy for efficient culling of large instance counts.

How HISM Works:

Instances are organized into an octree spatial structure. The system culls entire octree nodes when outside the view frustum, avoiding per-instance culling overhead.

Octree structure based globe space partitioning

Source: Chen, J. et al. (2018). Octree structure based globe space partitioning. ResearchGate. Available at: https://www.researchgate.net/figure/Octree-structure-based-globe-space-partitioning_fig8_322605170 [Accessed 14 Oct. 2025].

Octree Organization:

The octree divides 3D space into nested cubic regions. Each node contains instances within its bounds. When a node is outside the camera frustum, all contained instances are culled together.

Performance Characteristics:

Use Cases:

Performance Comparison

Metric ISM HISM
Draw Calls 1 per mesh type 1 per mesh type
Culling All-or-nothing Hierarchical
Instance Limit ~1,000 practical Millions
Memory Overhead Minimal Slight (octree)
Setup Complexity Simple Automatic
Best For Small groups Large populations

Material Consistency:

Instances sharing the same mesh and material batch together. Instances with different materials require separate draw calls.

Use material instances (not unique materials) for variation. Material instances share the same shader, maintaining batching while allowing parameter differences.

Culling Distance:

Set appropriate cull distances per foliage type. Grass culls at 10-20m, trees cull at 50-100m. Don’t render instances too far to see—wasted GPU cycles.

For less pop in, use distance blend opacity (dither not translucency)

LOD Configuration:

Always configure LOD chains for foliage meshes. Without LODs, distant instances render at full detail, wasting performance.

Target LOD 0 for 0-10m, LOD 1 for 10-25m, LOD 2 for 25-50m, LOD 3+ for 50m+. Use billboard LODs beyond 100m for maximum efficiency.

Collision Settings:

Foliage rarely needs complex collision. Use simple collision (box, sphere, capsule) or no collision for background vegetation.

Enable collision only for foliage requiring gameplay interaction (trees players can hide behind, bushes providing cover).

Foliage Types

What are Foliage Types?

A Foliage Type is a configuration asset that defines how a static mesh behaves when placed through the Foliage System, controlling placement rules, rendering settings, and instance properties.

Think of Foliage Types as templates. The static mesh defines geometry, the Foliage Type defines how that geometry is placed and rendered in the world.

Foliage Type Configuration:

  • Mesh reference: Which static mesh to instance
  • Density settings: How many instances per area
  • Placement rules: Slope, height, and alignment constraints
  • Instance variation: Scale, rotation, and color randomization
  • Rendering settings: LOD, culling, and shadow configuration
  • Collision properties: Collision complexity and interaction

One static mesh can have multiple Foliage Types with different settings. A tree mesh might have “Forest_Tree” (dense, small scale) and “Hero_Tree” (sparse, large scale) Foliage Types.

![Placeholder Image 038: Foliage Type asset configuration interface]

How to create and configure Foliage Types?

Create Foliage Type Asset

From Static Mesh:

Right-click a static mesh in the Content Browser. Select “Create Foliage Type.” This generates a Foliage Type asset referencing that mesh.

Name the asset descriptively: “FT_Oak_Tree”, “FT_Grass_Clump”, “FT_Rock_Small”. The “FT_” prefix helps identify Foliage Type assets.

From Foliage Mode:

Open Foliage Mode (Shift+3). Drag a static mesh into the Foliage Types panel. The system automatically creates a Foliage Type asset.

This workflow is faster for quick iteration but provides less control over asset naming and location.

Density Settings

Density (Instances per 1000cm²):

Controls how many instances are placed when painting. Higher density = more instances, denser coverage.

Typical Values:

Radius:

Defines the brush size for painting in Unreal units (cm). Larger radius covers more area quickly but reduces precision.

Start with 500-1000cm for detail work, 2000-5000cm for broad coverage.

Align to Normal:

When enabled, instances align perpendicular to the surface normal. Enable for grass and ground cover (follows terrain slope). Disable for trees (always upright regardless of slope).

Static Mesh vs Actor Foliage

Static Mesh Foliage

Type: Instanced Static Mesh components.

Characteristics: Pure rendering instances with no actor overhead or Blueprint logic—maximum performance.

Capabilities: Transform only (position/rotation/scale), material-instance variation, LOD and culling, simple collision.

Limitations: No gameplay logic, animation (beyond materials), runtime behavior, or component attachment.

Best For: Background vegetation, ground cover, decor—99% of foliage use cases.

Actor Foliage

Type: Full Actor instances.

Characteristics: Complete actor functionality, Blueprint logic, component hierarchies—higher overhead.

Capabilities: Gameplay behavior, animation, component attachment, and event handling.

Limitations: Higher memory and rendering cost, reduced feasible counts, requires careful optimization.

Best For: Interactive/animated plants and gameplay-critical foliage—special cases only.

Recommendation: Use Static Mesh Foliage for 99% of cases. Reserve Actor Foliage for special situations requiring gameplay logic or animation that can’t be achieved through materials.

Landscape Grass Output

What is Landscape Grass Output?

Landscape Grass Output is a material-driven foliage placement system that automatically spawns grass and ground cover based on landscape layer weight maps.

Instead of manually painting foliage, Landscape Grass Output reads weight maps from your landscape material and spawns foliage wherever specific layers are painted. Paint grass layer on landscape = grass foliage automatically appears.

Landscape Grass Output Features:

  • Material-driven: Foliage placement controlled by landscape layers
  • Automatic distribution: No manual foliage painting required
  • Density control: Grass density tied to layer weight
  • Performance optimized: Efficient for ground cover vegetation
  • Seamless integration: Works with existing landscape materials

This system is great for ground cover that should match landscape materials. Grass appears where grass texture is painted, flowers appear where flower texture is painted—automatic correlation.

The Fantastic Planet – Autolandscape

Source: “The Fantastic Planet” (n.d.). ArtStation. Available at: https://thefantasticplanet.artstation.com/projects/Ry62kr?album_id=6661199 [Accessed 14 Oct. 2025].

How to set up Landscape Grass Output?

Create Grass Type Asset

Create a Landscape Grass Type asset in the Content Browser. This asset defines which foliage meshes spawn and their properties.

Grass Varieties:

Add grass varieties using the “+” button. Each variety represents a different foliage mesh with independent settings.

Grass Mesh: Static mesh to spawn
Grass Density: Instances per 1000cm² (similar to Foliage Type density)
Start/End Cull Distance: Visibility range for this grass type
Min/Max Scale: Size variation range
Random Rotation: Enable for natural appearance

Example Configuration:

Variety 0: Tall grass (density 30, scale 0.9-1.2)
Variety 1: Short grass (density 50, scale 0.7-1.0)
Variety 2: Flowers (density 10, scale 0.8-1.1)

Multiple varieties create natural-looking mixed ground cover.

Add Landscape Grass Output Node

Open your landscape material. Add a “Landscape Grass Output” node.

Configure Node:

Add grass types using the “+” button in the node properties. For each grass type:

Name: Descriptive identifier (e.g., “Long_Grass”)
Grass Type: Reference to Landscape Grass Type asset
Weight: Connect to layer weight or custom mask

Weight Connection:

Connect a LandscapeLayerWeight node reading your grass layer to the Weight input. Grass density scales with layer weight:

This creates automatic correlation between painted landscape layer and spawned foliage.

Landscape Grass Output vs Manual Painting

Landscape Grass Output

Workflow: Paint landscape layers and foliage spawns automatically with density tied to layer weights; no separate foliage pass.

Advantages: Terrain-material correlation, fast coverage of large areas, consistent distribution, easy density control.

Limitations: Less direct artistic control; tied to landscape layers; requires material setup; best for ground cover.

Best For: Grass and ground cover, large-scale distribution, material-correlated vegetation, automated workflows.

Manual Foliage Painting

Workflow: Paint foliage directly, independent of landscape layers; full artistic control in a separate pass.

Advantages: Complete placement control, works on any surface, deliberate artistic refinement, flexible density.

Limitations: Time-consuming for large areas, manual effort, no automatic correlation with terrain materials.

Best For: Trees and bushes, hero vegetation, bespoke composition, non-ground-cover foliage.

Hybrid Approach:

Use Landscape Grass Output for ground cover (grass, flowers, small plants). Use manual foliage painting for trees, bushes, and hero vegetation. This combines automation efficiency with artistic control.

Any questions?

1 / 7